package com.googlecode.horncomb.web.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.apache.commons.beanutils.NestedNullException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.util.ExpressionEvaluationUtils;

import com.googlecode.horncomb.util.lang.BeanUtils;
import com.googlecode.horncomb.util.lang.MapConverter;

public abstract class TagUtils {
	protected static final Log logger = LogFactory.getLog(TagUtils.class);

	public static boolean getBooleanValue(String attributeName, Object value,
			PageContext pageContext) throws JspException {
		Object evaluatedValue = null;
		if (value instanceof String) {
			evaluatedValue = ExpressionEvaluationUtils.evaluate(attributeName,
					(String) value, pageContext);
		} else {
			evaluatedValue = value;
		}
		if (Boolean.class.isInstance(evaluatedValue)
				|| boolean.class.isInstance(evaluatedValue)) {
			return Boolean.TRUE.equals(evaluatedValue);
		} else if (String.class.isInstance(evaluatedValue)) {
			return Boolean.parseBoolean((String) evaluatedValue);
		}
		return false;
	}

	/**
	 * parse query string. split into name-values map from url after '?'
	 * @param query
	 * @param encoding
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static Map<String, String[]> parseQueryString(String query,
			String encoding) throws UnsupportedEncodingException {
		if (!StringUtils.hasText(query)) {
			return new HashMap<String, String[]>();
		}
		String[] params = query.split("&");
		Map<String, String[]> map = new HashMap<String, String[]>();
		for (String param : params) {
			String[] nvPare = param.split("=");
			if (nvPare == null || nvPare.length == 0)
				continue;

			String name = nvPare[0];
			String value = nvPare.length == 1 ? null : URLDecoder.decode(
					nvPare[1], encoding);
			String[] paramVals = null;
			if (map.containsKey(name)) {
				paramVals = StringUtils.addStringToArray(map.get(name), value);
			} else {
				paramVals = new String[] { value };
			}
			map.put(name, paramVals);
		}
		return map;
	}

	public static String buildQueryString(Map<String, String[]> parameters,
			String encoding) {
		StringBuilder sb = new StringBuilder();
		boolean first = true;
		for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
			try {
				String key = entry.getKey();
				if (!StringUtils.hasText(key)) {
					continue;
				}

				for (String val : entry.getValue()) {
					sb.append(first ? "" : "&").append(key).append("=")
							.append(
									val == null ? "" : URLEncoder.encode(val,
											encoding));
					first = false;
				}
			} catch (UnsupportedEncodingException e) {
				logger.warn(e);
			}
		}
		return sb.toString();
	}

	/**
	 * 解析分拆字符串为集合
	 * @param idStr
	 * @return
	 */
	public static Set<String> splitIdString(String idStr) {
		final Set<String> ids = new HashSet<String>();
		final String[] idAry = StringUtils
				.commaDelimitedListToStringArray(idStr);
		// final String[] idAry = StringUtils.delimitedListToStringArray(idStr,
		// ",", "\t\r\n\f");

		for (String id : idAry) {
			id = id.trim();
			id = StringUtils.replace(id, "\t", "");
			id = StringUtils.replace(id, "\r", "");
			id = StringUtils.replace(id, "\n", "");
			id = StringUtils.replace(id, "\f", "");
			ids.add(id);
		}

		return ids;
	}

	/**
	 * 根据传入的bean集合与要获取的属性名，返回属性值的集合
	 * @param obj
	 *            Beans' collection or iterator whose property is to be
	 *            extracted
	 * @param names
	 *            Possibly indexed and/or nested names of the properties to be
	 *            extracted
	 * @return the value set of the specified property of the specified bean set
	 */
	@SuppressWarnings("unchecked")
	public static Set<Object> parseIdString(Object obj, String... names) {
		Iterator iter = null;
		if (obj instanceof Iterator) {
			iter = (Iterator) obj;
		} else if (obj instanceof Collection) {
			iter = ((Collection) obj).iterator();
		}

		final Set<Object> ids = new HashSet<Object>();
		if (iter == null) {
			return ids;
		}
		while (iter.hasNext()) {
			try {
				Object o = iter.next();
				if (o != null) {
					Object val = null;
					for (String name : names) {
						if (o instanceof Map) {
							val = ((Map) o).get(name);
						} else {
							val = BeanUtils.getNullablePropertyValue(o, name);
						}
						if (val != null) {
							ids.add(val);
						}
					}
				}
			} catch (NestedNullException e) {
				logger.debug("忽略属性读取错误：" + e.toString());
			}
		}
		return ids;
	}

	/**
	 * 将Collection转化为以keyPropertyName为key的Map
	 * @param beans
	 * @param keyPropertyName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map convertToMap(Collection beans, String keyPropertyName) {
		HashMap map = new HashMap();
		if (beans == null) {
			return map;
		} else {
			return MapConverter.getPropertyMap(beans, keyPropertyName, null);
		}
	}

}
